# -*- coding: utf-8 -*-
"""
主窗口类
实现窗口布局管理、UI区域定位、组件交互逻辑和窗口重绘机制
"""

import pygame
import sys
import threading
from typing import Optional, Dict, Any
from gui.components.base_component import ComponentManager
from gui.components.input_box import InputBox
from gui.components.button import Button, IconButton
from gui.components.text_area import TextArea
from gui.components.file_dialog import FolderDialog
from gui.styles.colors import get_theme_color, set_theme, get_current_theme
from gui.styles.fonts import get_font
from config import WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE
from core import BilibiliDownloader, BilibiliAPI, DownloadStatus, DownloadProgress


class MainWindow:
    """主窗口类
    
    管理整个应用程序的主窗口，包括布局、组件管理和事件处理
    """
    
    def __init__(self):
        # 窗口基本属性
        self.width = WINDOW_WIDTH
        self.height = WINDOW_HEIGHT
        self.title = WINDOW_TITLE
        
        # Pygame相关
        self.screen: Optional[pygame.Surface] = None
        self.clock = pygame.time.Clock()
        self.running = False
        
        # 组件管理器
        self.component_manager = ComponentManager()
        
        # 布局区域定义
        self.layout_areas = self._define_layout_areas()
        
        # 组件引用（便于访问）
        self.components: Dict[str, Any] = {}
        
        # 窗口状态
        self.needs_redraw = True
        self.last_update_time = 0
        
        # 核心功能
        self.api = BilibiliAPI()
        self.downloader = BilibiliDownloader(max_concurrent_downloads=3)
        self.current_task_id: Optional[str] = None
        self.video_info: Optional[Dict] = None
        
        # 初始化窗口和组件
        self._init_pygame()
        self._create_components()
        self._setup_component_callbacks()
    
    def _define_layout_areas(self) -> Dict[str, Dict[str, int]]:
        """定义布局区域
        
        Returns:
            Dict: 各个区域的位置和尺寸信息
        """
        padding = 20
        
        areas = {
            # URL输入区域（顶部）
            'url_input': {
                'x': padding,
                'y': padding,
                'width': self.width - 2 * padding,
                'height': 80
            },
            
            # 视频信息区域（中上部）
            'video_info': {
                'x': padding,
                'y': padding + 80 + 10,
                'width': self.width - 2 * padding,
                'height': 120
            },
            
            # 下载设置区域（中部）
            'download_settings': {
                'x': padding,
                'y': padding + 80 + 10 + 120 + 10,
                'width': self.width - 2 * padding,
                'height': 80
            },
            
            # 控制按钮区域（中下部）
            'control_buttons': {
                'x': padding,
                'y': padding + 80 + 10 + 120 + 10 + 80 + 10,
                'width': self.width - 2 * padding,
                'height': 60
            },
            
            # 日志显示区域（底部）
            'log_area': {
                'x': padding,
                'y': padding + 80 + 10 + 120 + 10 + 80 + 10 + 60 + 10,
                'width': self.width - 2 * padding,
                'height': self.height - (padding + 80 + 10 + 120 + 10 + 80 + 10 + 60 + 10) - padding
            }
        }
        
        return areas
    
    def _init_pygame(self):
        """初始化Pygame"""
        pygame.init()
        
        # 创建窗口
        self.screen = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption(self.title)
        
        # 设置窗口图标（如果有的话）
        try:
            # icon = pygame.image.load('assets/icon.png')
            # pygame.display.set_icon(icon)
            pass
        except Exception:
            pass
    
    def _create_components(self):
        """创建所有UI组件"""
        # URL输入区域组件
        self._create_url_input_components()
        
        # 视频信息区域组件
        self._create_video_info_components()
        
        # 下载设置区域组件
        self._create_download_settings_components()
        
        # 控制按钮区域组件
        self._create_control_button_components()
        
        # 日志显示区域组件
        self._create_log_area_components()
        
        # 其他功能组件
        self._create_utility_components()
    
    def _create_url_input_components(self):
        """创建URL输入区域组件"""
        area = self.layout_areas['url_input']
        
        # URL输入标签（使用文本渲染）
        # 这里可以创建一个Label组件，暂时在绘制时处理
        
        # URL输入框
        input_width = area['width'] - 120  # 留出按钮空间
        url_input = InputBox(
            x=area['x'],
            y=area['y'] + 25,  # 留出标签空间
            width=input_width,
            height=35
        )
        url_input.set_placeholder('请输入B站视频链接...')
        url_input.set_validator(self._validate_bilibili_url)
        
        # 解析按钮
        parse_button = Button(
            x=area['x'] + input_width + 10,
            y=area['y'] + 25,
            width=100,
            height=35,
            text='获取信息'
        )
        parse_button.set_button_type('primary')
        
        # 添加到组件管理器
        self.component_manager.add_component('url_input', url_input)
        self.component_manager.add_component('parse_button', parse_button)
        
        # 保存引用
        self.components['url_input'] = url_input
        self.components['parse_button'] = parse_button
    
    def _create_video_info_components(self):
        """创建视频信息区域组件"""
        area = self.layout_areas['video_info']
        
        # 视频信息显示区域（使用TextArea显示）
        info_area = TextArea(
            x=area['x'],
            y=area['y'],
            width=area['width'],
            height=area['height']
        )
        info_area.set_auto_scroll(False)  # 信息区域不需要自动滚动
        
        self.component_manager.add_component('video_info_area', info_area)
        self.components['video_info_area'] = info_area
    
    def _create_download_settings_components(self):
        """创建下载设置区域组件"""
        area = self.layout_areas['download_settings']
        
        # 下载路径选择
        path_dialog = FolderDialog(
            x=area['x'],
            y=area['y'] + 25,  # 留出标签空间
            width=area['width'] - 120,  # 留出按钮空间
            height=35
        )
        
        # 文件名输入框
        filename_input = InputBox(
            x=area['x'] + area['width'] - 110,
            y=area['y'] + 25,
            width=100,
            height=35
        )
        filename_input.set_placeholder('文件名')
        
        self.component_manager.add_component('path_dialog', path_dialog)
        self.component_manager.add_component('filename_input', filename_input)
        
        self.components['path_dialog'] = path_dialog
        self.components['filename_input'] = filename_input
    
    def _create_control_button_components(self):
        """创建控制按钮区域组件"""
        area = self.layout_areas['control_buttons']
        
        button_width = 100
        button_height = 40
        button_spacing = 15
        
        # 计算按钮起始位置（居中排列）
        total_buttons = 4
        total_width = total_buttons * button_width + (total_buttons - 1) * button_spacing
        start_x = area['x'] + (area['width'] - total_width) // 2
        button_y = area['y'] + (area['height'] - button_height) // 2
        
        # 开始下载按钮
        download_button = Button(
            x=start_x,
            y=button_y,
            width=button_width,
            height=button_height,
            text='开始下载'
        )
        download_button.set_button_type('success')
        
        # 暂停/继续按钮
        pause_button = Button(
            x=start_x + (button_width + button_spacing),
            y=button_y,
            width=button_width,
            height=button_height,
            text='暂停'
        )
        pause_button.set_button_type('secondary')
        pause_button.set_enabled(False)  # 初始禁用
        
        # 停止下载按钮
        stop_button = Button(
            x=start_x + 2 * (button_width + button_spacing),
            y=button_y,
            width=button_width,
            height=button_height,
            text='停止'
        )
        stop_button.set_button_type('danger')
        stop_button.set_enabled(False)  # 初始禁用
        
        # 清空日志按钮
        clear_button = Button(
            x=start_x + 3 * (button_width + button_spacing),
            y=button_y,
            width=button_width,
            height=button_height,
            text='清空日志'
        )
        clear_button.set_button_type('secondary')
        
        # 添加到组件管理器
        self.component_manager.add_component('download_button', download_button)
        self.component_manager.add_component('pause_button', pause_button)
        self.component_manager.add_component('stop_button', stop_button)
        self.component_manager.add_component('clear_button', clear_button)
        
        # 保存引用
        self.components['download_button'] = download_button
        self.components['pause_button'] = pause_button
        self.components['stop_button'] = stop_button
        self.components['clear_button'] = clear_button
    
    def _create_log_area_components(self):
        """创建日志显示区域组件"""
        area = self.layout_areas['log_area']
        
        # 日志显示区域
        log_area = TextArea(
            x=area['x'],
            y=area['y'],
            width=area['width'],
            height=area['height']
        )
        log_area.set_auto_scroll(True)
        log_area.set_max_lines(500)  # 限制日志行数
        
        self.component_manager.add_component('log_area', log_area)
        self.components['log_area'] = log_area
        
        # 添加欢迎信息
        self.log_info('欢迎使用B站视频下载器！')
        self.log_info('请输入视频链接并点击"获取信息"按钮开始。')
    
    def _create_utility_components(self):
        """创建其他功能组件"""
        # 主题切换按钮（右上角）
        # 创建一个简单的文本图标
        font = get_font('button')
        icon_surface = font.get_font().render('🌙', True, (255, 255, 255))
        
        theme_button = IconButton(
            x=self.width - 50,
            y=10,
            size=40,
            icon=icon_surface
        )
        
        self.component_manager.add_component('theme_button', theme_button)
        self.components['theme_button'] = theme_button
    
    def _setup_component_callbacks(self):
        """设置组件回调函数"""
        # URL解析按钮回调
        self.components['parse_button'].on_click = self._on_parse_url
        
        # 下载控制按钮回调
        self.components['download_button'].on_click = self._on_start_download
        self.components['pause_button'].on_click = self._on_pause_download
        self.components['stop_button'].on_click = self._on_stop_download
        self.components['clear_button'].on_click = self._on_clear_log
        
        # 主题切换按钮回调
        self.components['theme_button'].on_click = self._on_toggle_theme
        
        # 路径选择回调
        self.components['path_dialog'].on_path_selected = self._on_path_selected
    
    def _validate_bilibili_url(self, url: str) -> bool:
        """验证B站URL格式"""
        if not url:
            return True  # 空URL也是有效的（用于清空状态）
        
        # 简单的B站URL验证
        bilibili_patterns = [
            'bilibili.com/video/',
            'b23.tv/',
            'BV',
            'av'
        ]
        
        return any(pattern in url.lower() for pattern in bilibili_patterns)
    
    # 事件回调函数
    def _on_parse_url(self):
        """解析URL按钮点击回调"""
        url = self.components['url_input'].get_text()
        if not url:
            self.log_warning('请输入视频链接！')
            return
        
        if not self._validate_bilibili_url(url):
            self.log_error('请输入有效的B站视频链接！')
            return
        
        self.log_info(f'正在解析视频链接: {url}')
        
        # 禁用解析按钮，防止重复点击
        self.components['parse_button'].set_enabled(False)
        self.components['parse_button'].set_text('解析中...')
        
        # 在后台线程中解析视频信息
        threading.Thread(target=self._parse_video_info, args=(url,), daemon=True).start()
    
    def _on_start_download(self):
        """开始下载按钮点击回调"""
        url = self.components['url_input'].get_text()
        path = self.components['path_dialog'].get_selected_path()
        
        if not url:
            self.log_warning('请先输入视频链接！')
            return
        
        if not path:
            self.log_warning('请先选择下载路径！')
            return
        
        if not self.video_info:
            self.log_warning('请先获取视频信息！')
            return
        
        # 创建下载任务
        filename = self.components['filename_input'].get_text()
        self.current_task_id = self.downloader.create_download_task(url, path, filename)
        
        if not self.current_task_id:
            self.log_error('创建下载任务失败！')
            return
        
        # 设置进度回调
        task = self.downloader.tasks[self.current_task_id]
        task.set_progress_callback(self._on_download_progress)
        task.set_completion_callback(self._on_download_complete)
        
        # 开始下载
        if self.downloader.start_download(self.current_task_id):
            self.log_info('开始下载视频...')
            
            # 更新按钮状态
            self.components['download_button'].set_enabled(False)
            self.components['pause_button'].set_enabled(True)
            self.components['stop_button'].set_enabled(True)
        else:
            self.log_error('启动下载失败！')
            self.current_task_id = None
    
    def _on_pause_download(self):
        """暂停下载按钮点击回调"""
        if not self.current_task_id:
            return
        
        button = self.components['pause_button']
        if button.text == '暂停':
            if self.downloader.pause_download(self.current_task_id):
                self.log_info('已暂停下载')
                button.set_text('继续')
        else:
            if self.downloader.resume_download(self.current_task_id):
                self.log_info('已继续下载')
                button.set_text('暂停')
    
    def _on_stop_download(self):
        """停止下载按钮点击回调"""
        if not self.current_task_id:
            return
        
        if self.downloader.stop_download(self.current_task_id):
            self.log_info('已停止下载')
            self.current_task_id = None
            
            # 重置按钮状态
            self.components['download_button'].set_enabled(True)
            self.components['pause_button'].set_enabled(False)
            self.components['pause_button'].set_text('暂停')
            self.components['stop_button'].set_enabled(False)
    
    def _on_clear_log(self):
        """清空日志按钮点击回调"""
        self.components['log_area'].clear()
        self.log_info('日志已清空')
    
    def _on_toggle_theme(self):
        """切换主题按钮点击回调"""
        current_theme = get_current_theme()
        new_theme = 'dark' if current_theme['name'] == 'light' else 'light'
        set_theme(new_theme)
        
        # 更新按钮图标
        icon = '☀️' if new_theme == 'light' else '🌙'
        self.components['theme_button'].set_text(icon)
        
        self.log_info(f'已切换到{"浅色" if new_theme == "light" else "深色"}主题')
        self.needs_redraw = True
    
    def _on_path_selected(self, path: str):
        """路径选择回调"""
        self.log_info(f'已选择下载路径: {path}')
    
    def _parse_video_info(self, url: str):
        """在后台线程中解析视频信息"""
        try:
            # 解析URL
            url_info = self.api.parse_video_url(url)
            if not url_info:
                pygame.event.post(pygame.event.Event(pygame.USEREVENT + 2, {'error': 'URL解析失败，请检查链接格式'}))
                return
            
            # 获取视频信息
            video_info = self.api.get_video_info(url_info['video_id'])
            if not video_info:
                pygame.event.post(pygame.event.Event(pygame.USEREVENT + 2, {'error': '获取视频信息失败，请检查网络连接'}))
                return
            
            # 发送成功事件
            pygame.event.post(pygame.event.Event(pygame.USEREVENT + 1, {'video_info': video_info}))
            
        except Exception as e:
            pygame.event.post(pygame.event.Event(pygame.USEREVENT + 2, {'error': str(e)}))
    
    def _reset_parse_button(self):
        """重置解析按钮状态"""
        pygame.event.post(pygame.event.Event(pygame.USEREVENT, {'action': 'reset_parse_button'}))
    
    def _update_video_info_display(self, video_info):
        """更新视频信息显示"""
        self.video_info = video_info
        
        if not self.video_info:
            return
        
        info_area = self.components['video_info_area']
        info_area.clear()
        
        # 显示基本信息
        info_area.add_line(f'标题: {self.video_info.get("title", "未知")}', 'info')
        info_area.add_line(f'UP主: {self.video_info.get("owner", {}).get("name", "未知")}', 'info')
        info_area.add_line(f'时长: {self._format_duration(self.video_info.get("duration", 0))}', 'info')
        info_area.add_line(f'播放量: {self._format_view_count(self.video_info.get("view_count", 0))}', 'info')
        
        # 显示分P信息
        pages = self.video_info.get('pages', [])
        if len(pages) > 1:
            info_area.add_line(f'分P数量: {len(pages)}', 'info')
        
        self.log_success('视频信息获取成功！')
    
    def _reset_parse_button(self):
        """重置解析按钮状态"""
        self.components['parse_button'].set_enabled(True)
        self.components['parse_button'].set_text('获取信息')
    
    def _format_duration(self, seconds: int) -> str:
        """格式化时长"""
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        seconds = seconds % 60
        
        if hours > 0:
            return f'{hours:02d}:{minutes:02d}:{seconds:02d}'
        else:
            return f'{minutes:02d}:{seconds:02d}'
    
    def _format_view_count(self, count: int) -> str:
        """格式化播放量"""
        if count >= 100000000:  # 1亿
            return f'{count / 100000000:.1f}亿'
        elif count >= 10000:  # 1万
            return f'{count / 10000:.1f}万'
        else:
            return str(count)
    
    def _on_download_progress(self, progress):
        """下载进度回调"""
        # 通过pygame事件系统在主线程中更新UI
        event = pygame.event.Event(pygame.USEREVENT + 3, {'progress': progress})
        pygame.event.post(event)
    
    def _on_download_complete(self, task_id, success):
        """下载完成回调"""
        # 通过pygame事件系统在主线程中更新UI
        event = pygame.event.Event(pygame.USEREVENT + 4, {
            'task_id': task_id,
            'success': success,
            'error_msg': None
        })
        pygame.event.post(event)
    
    def _update_download_progress(self, progress):
        """更新下载进度显示"""
        if progress.total_size > 0:
            percent = (progress.downloaded_size / progress.total_size) * 100
            
            # 格式化显示信息
            from core.utils import format_file_size, format_speed
            size_info = f"{format_file_size(progress.downloaded_size)}/{format_file_size(progress.total_size)}"
            speed_info = format_speed(progress.speed)
            eta_info = progress.eta
            
            progress_text = f"下载进度: {percent:.1f}% ({size_info}) 速度: {speed_info} 剩余: {eta_info}"
            self.log_info(progress_text)
    
    def _handle_download_complete(self, task_id, success, error_msg):
        """处理下载完成事件"""
        if success:
            self.log_success('下载完成！')
        else:
            self.log_error(f'下载失败: {error_msg or "未知错误"}')
        
        # 重置状态
        self.current_task_id = None
        
        # 重置按钮状态
        self.components['download_button'].set_enabled(True)
        self.components['pause_button'].set_enabled(False)
        self.components['pause_button'].set_text('暂停')
        self.components['stop_button'].set_enabled(False)
    
    # 日志记录方法
    def log_info(self, message: str):
        """记录信息日志"""
        self.components['log_area'].add_line(f'[信息] {message}', 'info')
    
    def log_warning(self, message: str):
        """记录警告日志"""
        self.components['log_area'].add_line(f'[警告] {message}', 'warning')
    
    def log_error(self, message: str):
        """记录错误日志"""
        self.components['log_area'].add_line(f'[错误] {message}', 'error')
    
    def log_success(self, message: str):
        """记录成功日志"""
        self.components['log_area'].add_line(f'[成功] {message}', 'success')
    
    def handle_event(self, event: pygame.event.Event):
        """处理事件"""
        # 窗口关闭事件
        if event.type == pygame.QUIT:
            self.running = False
            return
        
        # 键盘事件
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                self.running = False
                return
        
        # 处理自定义事件
        if event.type == pygame.USEREVENT + 1:  # 视频信息解析完成
            self._update_video_info_display(event.video_info)
            self._reset_parse_button()
        elif event.type == pygame.USEREVENT + 2:  # 视频信息解析失败
            self.log_error(f'解析失败: {event.error}')
            self._reset_parse_button()
        elif event.type == pygame.USEREVENT + 3:  # 下载进度更新
            self._update_download_progress(event.progress)
        elif event.type == pygame.USEREVENT + 4:  # 下载完成
            self._handle_download_complete(event.task_id, event.success, event.error_msg)
        
        # 将事件传递给组件管理器
        if self.component_manager.handle_event(event):
            self.needs_redraw = True
    
    def update(self, dt: float):
        """更新窗口状态"""
        # 更新组件
        self.component_manager.update(dt)
        
        # 检查是否需要重绘
        current_time = pygame.time.get_ticks()
        if current_time - self.last_update_time > 16:  # 约60FPS
            self.needs_redraw = True
            self.last_update_time = current_time
    
    def draw(self):
        """绘制窗口"""
        if not self.needs_redraw:
            return
        
        # 清空屏幕
        self.screen.fill(get_theme_color('background'))
        
        # 绘制区域标签
        self._draw_area_labels()
        
        # 绘制所有组件
        self.component_manager.draw(self.screen)
        
        # 更新显示
        pygame.display.flip()
        self.needs_redraw = False
    
    def _draw_area_labels(self):
        """绘制区域标签"""
        font = get_font('label')
        label_color = get_theme_color('text')
        
        labels = [
            ('视频链接:', self.layout_areas['url_input']['x'], self.layout_areas['url_input']['y']),
            ('视频信息:', self.layout_areas['video_info']['x'], self.layout_areas['video_info']['y'] - 20),
            ('下载设置:', self.layout_areas['download_settings']['x'], self.layout_areas['download_settings']['y']),
            ('下载日志:', self.layout_areas['log_area']['x'], self.layout_areas['log_area']['y'] - 20)
        ]
        
        for label_text, x, y in labels:
            text_surface = font.get_font().render(label_text, True, label_color)
            self.screen.blit(text_surface, (x, y))
    
    def run(self):
        """运行主循环"""
        self.running = True
        
        while self.running:
            dt = self.clock.tick(60) / 1000.0  # 转换为秒
            
            # 处理事件
            for event in pygame.event.get():
                self.handle_event(event)
            
            # 更新
            self.update(dt)
            
            # 绘制
            self.draw()
        
        # 清理资源
        pygame.quit()
        sys.exit()


if __name__ == '__main__':
    # 测试主窗口
    window = MainWindow()
    window.run()